/*
 * Timer Example
 *
 * Desc: a simple example to create periodic timer
 * Usage: ./test.sh
 *   myapp 1   create a periodic timer
 *   sleep a while
 *   myapp 3   destroy the timer
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>

#include <linux/miscdevice.h>
#include <linux/workqueue.h>
#include <linux/timer.h>

#include "my_common.h"

#define TIMER_PERIODIC (2 * HZ)

static struct timer_list my_timer;

static void my_timer_fn(struct timer_list *timer)
{
	pr_info("jiffies=%ld\n", jiffies);
	mod_timer(&my_timer, jiffies + TIMER_PERIODIC);
}

static void do_ioctl_cmd1(void)
{
	timer_setup(&my_timer, my_timer_fn, 0);
	my_timer.expires = jiffies + TIMER_PERIODIC;
	add_timer(&my_timer);
}

static void do_ioctl_cmd2(void)
{
}

static void do_ioctl_cmd3(void)
{
	del_timer(&my_timer);
}

static long mydrv_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	switch (cmd) {
	case CMD1:
		do_ioctl_cmd1();
		break;
	case CMD2:
		do_ioctl_cmd2();
		break;
	case CMD3:
		do_ioctl_cmd3();
		break;
	default:
		pr_err("Doesn't support cmd %d\n", cmd);
	}

	return 0;
}

static struct file_operations mydrv_fops = {
	.owner = THIS_MODULE,
	.unlocked_ioctl = mydrv_ioctl,
};


static struct miscdevice mydrv_misc_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "mydev",
	.fops = &mydrv_fops,
};

static int __init mydrv_init(void)
{
	int ret;

	pr_info("%s...\n", __func__);

	ret = misc_register(&mydrv_misc_dev);
	if (ret) {
		pr_err("%s: misc_register failed, errno=%d\n", __func__, ret);
		return ret;
	}

	return 0;
}

static void __exit mydrv_exit(void)
{
	pr_info("%s...\n", __func__);
	misc_deregister(&mydrv_misc_dev);
}

module_init(mydrv_init);
module_exit(mydrv_exit);

MODULE_AUTHOR("mydrv");
MODULE_LICENSE("GPL");
